package me.itsoo.artemis.framework.repository.datasource;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import me.itsoo.artemis.framework.repository.config.Configuration;
import me.itsoo.artemis.framework.repository.exception.CreatedConnectionException;

import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * DataSourceManager
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/18
 */
@Slf4j
public class DataSourceManager2 {

    private final Configuration config;

    private final LinkedBlockingQueue<Connection> activePool;

    private final int coreSize;

    private final int maxSize;

    private final int maxWait;

    private final AtomicInteger createdCounter = new AtomicInteger(0);

    public DataSourceManager2(Configuration config) {
        this.config = config;
        this.activePool = new LinkedBlockingQueue<>(config.getCoreSize());

        this.coreSize = config.getCoreSize();
        this.maxSize = config.getMaxSize();
        this.maxWait = config.getMaxWait();

        init();
    }

    private void init() {
        try {
            Class.forName(config.getDriverClassName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        for (int i = 0; i < coreSize; i++) {
            activePool.add(getConnection0());
            createdCounter.incrementAndGet();
        }
    }

    //    @Override
    public Connection getConnection(boolean autoCommit) {
        final Connection result = getConnection();
        result.setAutoCommit(autoCommit);
        log.info("<{}> [create]:{}, [free]:{}, [total]:{}",
                Thread.currentThread().getId(), createdCounter.get(), activePool.size(), maxSize);
        return result;
    }

    private Connection getConnection() {
        Connection result = activePool.poll();
        if (Objects.nonNull(result)) {
            return result;
        }

        if (createdCounter.incrementAndGet() <= maxSize) {
            result = getConnection0();
            return result;
        } else {
            // 未获取到连接需要计数器 -1
            createdCounter.decrementAndGet();
        }

        try {
            result = activePool.poll(maxWait, TimeUnit.MILLISECONDS);
            if (Objects.nonNull(result)) {
                return result;
            }
            throw new InterruptedException("fire");
        } catch (InterruptedException e) { // NOSONAR
            throw new CreatedConnectionException(coreSize, maxSize);
        }
    }

    private Connection getConnection0() {
        try {
//            return DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
            return Connection.create(String.valueOf(System.currentTimeMillis()));
//        } catch (SQLException e) {
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //    @Override
    public void releaseConnection(Connection conn) {
        if (createdCounter.decrementAndGet() >= coreSize) {
//            conn.close();
        } else {
            activePool.add(conn);
        }

        log.info("[释放] <{}> [create]:{}, [free]:{}, [total]:{}",
                Thread.currentThread().getId(), createdCounter.get(), activePool.size(), maxSize);
    }


    @Data
    public static class Connection {
        final String a;
        boolean ac;

        Connection(String a) {
            this.a = a;
        }

        boolean getAutoCommit() {
            return ac;
        }

        void setAutoCommit(boolean autoCommit) {
            this.ac = autoCommit;
        }

        static Connection create(String a) {
            return new Connection(a);
        }
    }
}
